/*
 *    Copyright 2022 The DSMS Authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.dsms.modules.alert.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsms.common.constant.*;
import com.dsms.common.exception.DsmsEngineException;
import com.dsms.modules.alert.entity.AlertMessage;
import com.dsms.modules.alert.mapper.AlertMessageMapper;
import com.dsms.modules.alert.model.vo.AlertMessageManageVO;
import com.dsms.modules.alert.model.vo.AlertMessagePageVO;
import com.dsms.modules.alert.model.vo.AlertMessageQueryVO;
import com.dsms.modules.alert.service.IAlertMessageService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


@Service
public class AlertMessageServiceImpl extends ServiceImpl<AlertMessageMapper, AlertMessage> implements IAlertMessageService {

    private static final int DEFAULT_RULE_ID = 0;

    @Override
    public Page<AlertMessage> listAlertMessage(AlertMessagePageVO alertMessagePageVO) {
        Page<AlertMessage> alertMessagePage = new Page<>(alertMessagePageVO.getPageNo(), alertMessagePageVO.getPageSize());
        LambdaQueryWrapper<AlertMessage> queryWrapper = new LambdaQueryWrapper<AlertMessage>()
                .eq(!ObjectUtil.isEmpty(alertMessagePageVO.getLevel()), AlertMessage::getLevel, alertMessagePageVO.getLevel())
                .eq(!ObjectUtil.isEmpty(alertMessagePageVO.getModel()), AlertMessage::getModule, alertMessagePageVO.getModel())
                .eq(!ObjectUtil.isEmpty(alertMessagePageVO.getStatus()), AlertMessage::getStatus, alertMessagePageVO.getStatus())
                .orderByAsc(AlertMessage::getStatus)
                .orderByDesc(AlertMessage::getCreateTime);
        alertMessagePage = this.page(alertMessagePage, queryWrapper);
        return alertMessagePage;
    }

    @Override
    public AlertMessage getAlertMessage(AlertMessageQueryVO alertMessageQueryVO) {
        LambdaQueryWrapper<AlertMessage> getAlertMessage = new LambdaQueryWrapper<AlertMessage>().eq(AlertMessage::getId, alertMessageQueryVO.getMessageId());
        return this.getOne(getAlertMessage);
    }

    @Override
    public boolean confirmMessage(AlertMessageManageVO alertMessageManageVO) {
        //parsing ids and deduplication
        HashSet<Integer> ids = new HashSet<>(alertMessageManageVO.getIds());
        //get the alarm message according to id, make sure the alarm message exists and unconfirmed
        List<AlertMessage> alertMessages = this.listByIds(ids);
        List<AlertMessage> confirmed = alertMessages.stream().filter(alertMessage -> Objects.equals(alertMessage.getStatus(), AlertMessageStatusEnum.CONFIRM.getStatus())).collect(Collectors.toList());
        if (!confirmed.isEmpty()) {
            throw DsmsEngineException.exceptionWithMessage("告警信息不能被重复确认", ResultCode.ALERT_MESSAGE_CONFIRM_ERROR);
        }

        //change the status to read
        alertMessages = alertMessages.stream().map(alertMessage -> alertMessage.setStatus(AlertMessageStatusEnum.CONFIRM.getStatus()).setUpdateTime(LocalDateTime.now())).collect(Collectors.toList());

        return this.updateBatchById(alertMessages);
    }

    @Override
    public boolean deleteMessage(AlertMessageManageVO alertMessageManageVO) {
        //parsing ids and deduplication
        HashSet<Integer> ids = new HashSet<>(alertMessageManageVO.getIds());
        //get the alarm message according to id, make sure the alarm message exists and confirmed
        List<AlertMessage> alertMessages = this.listByIds(ids);
        List<AlertMessage> unconfirmed = alertMessages.stream().filter(alertMessage -> Objects.equals(alertMessage.getStatus(), AlertMessageStatusEnum.UN_CONFIRM.getStatus())).collect(Collectors.toList());
        if (!unconfirmed.isEmpty()) {
            throw DsmsEngineException.exceptionWithMessage("未读的告警信息不能被删除", ResultCode.ALERT_MESSAGE_DELETE_ERROR);
        }

        return this.removeBatchByIds(ids);
    }

    @Override
    public long getUnconfirmedMessageNum() {
        LambdaQueryWrapper<AlertMessage> unconfirmedAlertMessage = new LambdaQueryWrapper<AlertMessage>().eq(AlertMessage::getStatus, AlertMessageStatusEnum.UN_CONFIRM.getStatus());
        return this.count(unconfirmedAlertMessage);
    }

    @Override
    public List<AlertMessage> getUnSendMessages() {
        LambdaQueryWrapper<AlertMessage> queryWrapper = new LambdaQueryWrapper<AlertMessage>()
                .eq(AlertMessage::getSmsStatus, AlertMessageAppriseStatusEnum.UP_BUT_NOT_APPRISED.getCode())
                .or().eq(AlertMessage::getEmailStatus, AlertMessageAppriseStatusEnum.UP_BUT_NOT_APPRISED.getCode());
        return this.list(queryWrapper);
    }

    @Override
    public AlertMessage convertCustomMessage(String message, AlertRuleModuleEnum alertRuleModuleEnum, AlertRuleLevelEnum alertRuleLevelEnum) {
        AlertMessage alertMessage = new AlertMessage();
        alertMessage.setStatus(AlertMessageStatusEnum.UN_CONFIRM.getStatus())
                .setLevel(alertRuleLevelEnum.getStatus())
                .setRuleId(DEFAULT_RULE_ID)
                .setContent(message)
                .setModule(alertRuleModuleEnum.getModuleCode())
                .setCreateTime(LocalDateTime.now())
                .setSmsStatus(AlertMessageAppriseStatusEnum.DOWN.getCode())
                .setEmailStatus(AlertMessageAppriseStatusEnum.DOWN.getCode());
        return alertMessage;
    }

}
